package com.axinfu.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Kit:Unicode
 *
 * @author zjn
 * @since 2022/3/23
 */
public class UnicodeConverter {

    /**
     * unicode表示正则匹配
     */
    public static final Pattern REG_UNICODE = Pattern.compile("[0-9A-Fa-f]{4}");

    private UnicodeConverter() {
    }

    /**
     * unicode转换过滤器
     */
    public interface UnicodeConverterFilter {

        /**
         * 是否忽略
         *
         * @param c 当前处理的字符
         * @return 忽略返回true，否则返回false
         */
        boolean isPass(char c);
    }

    /**
     * 全部转换
     */
    public static final UnicodeConverterFilter UNICODE_CONVERTER_FILTER4_ALL = c -> false;

    /**
     * 转换非Ascii码字符
     */
    public static final UnicodeConverterFilter UNICODE_CONVERTER_FILTER4_NOT_ASCII =
            c -> (int) c >= 33 && (int) c <= 126;

    /**
     * unicode编码
     *
     * @param str                    待编码字符串
     * @param unicodeConverterFilter 字符过滤器
     * @return 编码后字符串
     */
    public static String encrypt(String str, UnicodeConverterFilter unicodeConverterFilter) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            // 取出每个字符
            char c = str.charAt(i);

            //处理忽略的字符
            if (unicodeConverterFilter.isPass(c)) {
                sb.append(c);
                continue;
            }

            //补位处理
            //转为16进制表示
            String cStr = Integer.toHexString(c);
            switch (4 - cStr.length()) {
                case 0:
                    sb.append("\\u").append(cStr);
                    break;
                case 1:
                    sb.append("\\u0").append(cStr);
                    break;
                case 2:
                    sb.append("\\u00").append(cStr);
                    break;
                case 3:
                    sb.append("\\u000").append(cStr);
                    break;
                default:
                    sb.append(c);
                    break;
            }
        }

        return sb.toString();
    }

    /**
     * unicode编码，编码所有字符
     *
     * @param str 待编码字符串
     * @return 编码后字符串
     */
    public static String encrypt4All(String str) {
        return encrypt(str, UNICODE_CONVERTER_FILTER4_ALL);
    }

    /**
     * unicode编码，编码非ascii码
     *
     * @param str 待编码字符串
     * @return 编码后字符串
     */
    public static String encrypt4NotAscii(String str) {
        return encrypt(str, UNICODE_CONVERTER_FILTER4_NOT_ASCII);
    }

    /**
     * unicode解码
     *
     * @param unicodeStr unicode编码的字符串
     * @return 解码后的字符串
     */
    public static String decrypt(String unicodeStr) {
        StringBuilder sb = new StringBuilder();
        int len = unicodeStr.length();
        for (int i = 0; i < len; i++) {
            //取出字符
            char c1 = unicodeStr.charAt(i);
            //获取到unicode标识\并不在末尾
            if (c1 == '\\' && i < len - 1) {
                //取出unicode标识下一位字符
                char c2 = unicodeStr.charAt(++i);
                //获取到unicode十六进制标识u并最后一段能组成完整unicode格式
                if (c2 == 'u' && i <= len - 5) {
                    //取出unicode格式\\uxxxx中的十六进制xxxx
                    String tmp = unicodeStr.substring(i + 1, i + 5);
                    //进行unicode四位十六进制正则匹配
                    Matcher matcher = REG_UNICODE.matcher(tmp);
                    //匹配成功
                    if (matcher.find()) {
                        //将十六进制转换为字符添加到结果
                        sb.append((char) Integer.parseInt(tmp, 16));
                        //处理下一个
                        i = i + 4;
                        //未匹配成功，直接将原始字符添加到结果
                    } else {
                        sb.append(c1).append(c2);
                    }
                } else {
                    //未获取到unicode十六进制标识u或最后一段不能组成完整unicode格式，直接将原始字符添加到结果
                    sb.append(c1).append(c2);
                }
            } else {
                //未获取到unicode标识\或在末尾
                sb.append(c1);
            }
        }
        return sb.toString();
    }
}
